/*
 * Copyright 2006-2023 ahtelit.com, All Rights Reserved.
 */

package com.telit.firecommand.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.telit.common.dto.DistrictDTO;
import com.telit.common.entity.PageData;
import com.telit.firecommand.dao.SciMeteoricDataDAO;
import com.telit.firecommand.dao.SciWaterQualityDataDAO;
import com.telit.firecommand.dao.SysEquipStationDAO;
import com.telit.firecommand.dao.SysEquipStationDataLogDAO;
import com.telit.firecommand.dto.DistrictCountDTO;
import com.telit.firecommand.dto.SciMeteoricDataDTO;
import com.telit.firecommand.dto.SciWaterQualityDataDTO;
import com.telit.firecommand.dto.SysEquipStationDTO;
import com.telit.firecommand.entity.SciMeteoricData;
import com.telit.firecommand.entity.SciWaterQualityData;
import com.telit.firecommand.entity.SysEquipStation;
import com.telit.firecommand.entity.SysEquipStationDataLog;
import com.telit.firecommand.service.DistrictService;
import com.telit.firecommand.service.EquipStationService;
import com.telit.firecommand.util.EquipStationUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


/**
 * EquipStationServiceImpl
 *
 * @author yuezhuang
 * @since 2023-03-31
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EquipStationServiceImpl implements EquipStationService {

    private final SysEquipStationDAO sysEquipStationDAO;

    private final SciWaterQualityDataDAO sciWaterQualityDataDAO;

    private final SciMeteoricDataDAO sciMeteoricDataDAO;

    private final DistrictService districtService;

    private final SysEquipStationDataLogDAO sysEquipStationDataLogDAO;

    /**
     * 查询数量
     *
     * @param districtCode 行政区划编码
     * @param type         监测站类型（1:气象站，2:水文站）
     * @param status       状态：1-在线 0-离线
     * @param name         名称
     *
     * @return DistrictCountDTO
     */
    @Override
    public DistrictCountDTO count(String districtCode, Integer type, Integer status, String name) {
        //判断在离线：6个小时之内是否有数据推送过来
        Date now = new Date();
        String end = DateUtil.format(now, DatePattern.NORM_DATETIME_PATTERN);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(now);
        calendar.add(Calendar.HOUR_OF_DAY, -6);
        String start = DateUtil.format(calendar.getTime(), DatePattern.NORM_DATETIME_PATTERN);

        long totalCount = sysEquipStationDAO.count(districtCode, true, type, null, name, start, end);
        long onlineCount = sysEquipStationDAO.count(districtCode, true, type, 1, name, start, end);
        return DistrictCountDTO.builder()
                .count((int) totalCount)
                .offlineCount((int) (totalCount - onlineCount))
                .onlineCount((int) onlineCount)
                .build();
    }

    /**
     * 查询数量
     *
     * @param districtCode 行政区划编码
     * @param type         监测站类型（1:气象站，2:水文站）
     * @param status       状态：1-在线 0-离线
     * @param name         名称
     *
     * @return DistrictCountDTO
     */
    @Override
    public DistrictCountDTO treeDistrict(String districtCode, Integer type, Integer status, String name) {
        //判断在离线：6个小时之内是否有数据推送过来
        Date now = new Date();
        String end = DateUtil.format(now, DatePattern.NORM_DATETIME_PATTERN);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(now);
        calendar.add(Calendar.HOUR_OF_DAY, -6);
        String start = DateUtil.format(calendar.getTime(), DatePattern.NORM_DATETIME_PATTERN);

        //当前行政区划信息
        DistrictDTO current = districtService.qryDistrictInfo(districtCode);
        //当前行政区划下护林员数量（包含子行政区划）
        long currentCount = sysEquipStationDAO.count(districtCode, true, type, status, name, start, end);
        //当前行政区划下列表（不包含子行政区划）
        List<SysEquipStation> sysEquipStations = new ArrayList<>();
        if (currentCount > 0) {
            sysEquipStations = sysEquipStationDAO.selectByCondition(districtCode, false, type, status, name, start, end,
                    Integer.MAX_VALUE, 0);
        }
        sysEquipStations = sysEquipStations.stream().peek(
                sysEquipStation -> {sysEquipStation.setOnlineStatus(sysEquipStation.isStatus() ? 1 : 0);}).collect(
                Collectors.toList());
        //构建返回DTO
        DistrictCountDTO districtCountDTO = DistrictCountDTO.builder()
                .id(current.getId())
                .name(current.getName())
                .code(current.getCode())
                .parentCode(current.getParentCode())
                .rank(current.getRank())
                .count((int) currentCount)
                .equipStationList(
                        sysEquipStations.stream().map(map -> Convert.convert(SysEquipStationDTO.class, map)).collect(
                                Collectors.toList()))
                .build();
        List<DistrictCountDTO> countChildren = new ArrayList<>();
        //子类行政区划集合
        List<DistrictDTO> children = districtService.qryListByParentCode(districtCode, null);
        String finalStart = start;
        String finalEnd = end;
        children.forEach(districtDTO -> {
            long childCount = sysEquipStationDAO.count(districtDTO.getCode(), true, type, status, name, finalStart,
                    finalEnd);
            List<SysEquipStation> childList = new ArrayList<>();
            if (childCount > 0) {
                childList = sysEquipStationDAO.selectByCondition(districtDTO.getCode(), false, type, status, name,
                        finalStart, finalEnd, Integer.MAX_VALUE, 0);
                childList = childList.stream().peek(
                        sysEquipStation -> {
                            sysEquipStation.setOnlineStatus(sysEquipStation.isStatus() ? 1 : 0);
                        }).collect(
                        Collectors.toList());
            }
            DistrictCountDTO countDTO = DistrictCountDTO.builder()
                    .id(districtDTO.getId())
                    .name(districtDTO.getName())
                    .code(districtDTO.getCode())
                    .parentCode(districtDTO.getParentCode())
                    .rank(districtDTO.getRank())
                    .count((int) childCount)
                    .equipStationList(
                            childList.stream().map(map -> Convert.convert(SysEquipStationDTO.class, map)).collect(
                                    Collectors.toList()))
                    .build();
            countChildren.add(countDTO);
        });
        districtCountDTO.setChildren(countChildren);
        return districtCountDTO;
    }

    /**
     * 详情
     *
     * @param id id
     *
     * @return SysEquipStationDTO
     */
    @Override
    public SysEquipStationDTO info(Long id) {
        //判断在离线：6个小时之内是否有数据推送过来
        Date now = new Date();
        String end = DateUtil.format(now, DatePattern.NORM_DATETIME_PATTERN);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(now);
        calendar.add(Calendar.HOUR_OF_DAY, -6);
        String start = DateUtil.format(calendar.getTime(), DatePattern.NORM_DATETIME_PATTERN);

        SysEquipStation sysEquipStation = sysEquipStationDAO.info(id, start, end);
        sysEquipStation.setOnlineStatus(sysEquipStation.isStatus() ? 1 : 0);

        LambdaQueryWrapper<SciWaterQualityData> sciWaterQualityDataLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sciWaterQualityDataLambdaQueryWrapper.eq(SciWaterQualityData::getCode, sysEquipStation.getCode());
        sciWaterQualityDataLambdaQueryWrapper.last("limit 1");
        sciWaterQualityDataLambdaQueryWrapper.orderByDesc(SciWaterQualityData::getId);
        SciWaterQualityData sciWaterQualityData = sciWaterQualityDataDAO.selectOne(
                sciWaterQualityDataLambdaQueryWrapper);
        SciWaterQualityDataDTO sciWaterQualityDataDTO = new SciWaterQualityDataDTO();
        if (sciWaterQualityData != null) {
            BeanUtils.copyProperties(sciWaterQualityData, sciWaterQualityDataDTO);
        }

        LambdaQueryWrapper<SciMeteoricData> sciMeteoricDataLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sciMeteoricDataLambdaQueryWrapper.eq(SciMeteoricData::getCode, sysEquipStation.getCode());
        sciMeteoricDataLambdaQueryWrapper.last("limit 1");
        sciMeteoricDataLambdaQueryWrapper.orderByDesc(SciMeteoricData::getId);
        SciMeteoricData sciMeteoricData = sciMeteoricDataDAO.selectOne(sciMeteoricDataLambdaQueryWrapper);
        SciMeteoricDataDTO sciMeteoricDataDTO = new SciMeteoricDataDTO();
        if (sciMeteoricData != null) {
            BeanUtils.copyProperties(sciMeteoricData, sciMeteoricDataDTO);
        }

        SysEquipStationDTO sysEquipStationDTO = new SysEquipStationDTO();
        BeanUtils.copyProperties(sysEquipStation, sysEquipStationDTO);
        sysEquipStationDTO.setSciMeteoricData(sciMeteoricDataDTO);
        sysEquipStationDTO.setSciWaterQualityData(sciWaterQualityDataDTO);

        return sysEquipStationDTO;
    }

    /**
     * 拉取数据
     */
    @Override
    public void dealData() {
        //设备列表
        Integer page = 1;
        Integer size = 100;
        List<SysEquipStation> equipStationList = EquipStationUtils.getEquipStationList(page, size, null).getDatas();
        equipStationList.forEach(sysEquipStation -> {
            SysEquipStation dbSysEquipStation = sysEquipStationDAO.selectById(sysEquipStation);
            if (dbSysEquipStation != null) {
                sysEquipStationDAO.updateById(sysEquipStation);
            } else {
                sysEquipStationDAO.insert(sysEquipStation);
            }
        });

        //初始化拉取最近7天的
        Date now = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(now);
        calendar.add(Calendar.DAY_OF_MONTH, -7);
        String startAt = DateUtil.format(calendar.getTime(), DatePattern.NORM_DATETIME_PATTERN);
        String endAt = DateUtil.format(now, DatePattern.NORM_DATETIME_PATTERN);
        //气象数据
        LambdaQueryWrapper<SysEquipStationDataLog> stationDataLogLambdaQueryWrapper = new LambdaQueryWrapper<>();
        stationDataLogLambdaQueryWrapper.eq(SysEquipStationDataLog::getUri, EquipStationUtils.GET_RAIN_PAGE_URI);
        SysEquipStationDataLog stationDataLog = sysEquipStationDataLogDAO.selectOne(stationDataLogLambdaQueryWrapper);
        if (stationDataLog != null) {
            startAt = DateUtil.format(stationDataLog.getEndAt(), DatePattern.NORM_DATETIME_PATTERN);
            List<SciMeteoricData> sciMeteoricDataList = EquipStationUtils.getRainList(page, size, null, startAt,
                    endAt).getDatas();
            if (CollectionUtil.isNotEmpty(sciMeteoricDataList)) {
                sciMeteoricDataDAO.insertBatchSomeColumn(sciMeteoricDataList);
            }

            stationDataLog.setStartAt(DateUtil.parse(startAt));
            stationDataLog.setEndAt(DateUtil.parse(endAt));
            sysEquipStationDataLogDAO.updateById(stationDataLog);
        } else {//判断是否有重复的数据
            List<SciMeteoricData> sciMeteoricDataList = EquipStationUtils.getRainList(page, size, null, startAt,
                    endAt).getDatas();
            if (CollectionUtil.isNotEmpty(sciMeteoricDataList)) {
                sciMeteoricDataList.forEach(sciMeteoricData -> {
                    SciMeteoricData dbSciMeteoricData = sciMeteoricDataDAO.selectById(sciMeteoricData.getId());
                    if (dbSciMeteoricData != null) {
                        sciMeteoricDataDAO.updateById(sciMeteoricData);
                    } else {
                        sciMeteoricDataDAO.insert(sciMeteoricData);
                    }
                });
            }

            SysEquipStationDataLog build = SysEquipStationDataLog.builder().startAt(DateUtil.parse(startAt)).endAt(
                    DateUtil.parse(endAt)).uri(EquipStationUtils.GET_RAIN_PAGE_URI).build();
            sysEquipStationDataLogDAO.insert(build);
        }

        //水文数据
        LambdaQueryWrapper<SysEquipStationDataLog> logLambdaQueryWrapper = new LambdaQueryWrapper<>();
        logLambdaQueryWrapper.eq(SysEquipStationDataLog::getUri, EquipStationUtils.GET_WATER_QUALITY_PAGE_URI);
        SysEquipStationDataLog dataLog = sysEquipStationDataLogDAO.selectOne(logLambdaQueryWrapper);
        if (dataLog != null) {
            startAt = DateUtil.format(dataLog.getEndAt(), DatePattern.NORM_DATETIME_PATTERN);
            List<SciWaterQualityData> waterQualityDataList = EquipStationUtils.getWaterQualityList(page, size, null,
                    startAt, endAt).getDatas();
            if (CollectionUtil.isNotEmpty(waterQualityDataList)) {
                sciWaterQualityDataDAO.insertBatchSomeColumn(waterQualityDataList);
            }

            dataLog.setStartAt(DateUtil.parse(startAt));
            dataLog.setEndAt(DateUtil.parse(endAt));
            sysEquipStationDataLogDAO.updateById(dataLog);
        } else {//判断是否有重复的数据
            List<SciWaterQualityData> waterQualityDataList = EquipStationUtils.getWaterQualityList(page, size, null,
                    startAt, endAt).getDatas();
            if (CollectionUtil.isNotEmpty(waterQualityDataList)) {
                waterQualityDataList.forEach(waterQualityData -> {
                    SciWaterQualityData sciWaterQualityData = sciWaterQualityDataDAO.selectById(
                            waterQualityData.getId());
                    if (sciWaterQualityData != null) {
                        sciWaterQualityDataDAO.updateById(waterQualityData);
                    } else {
                        sciWaterQualityDataDAO.insert(waterQualityData);
                    }
                });
            }

            SysEquipStationDataLog build = SysEquipStationDataLog.builder().startAt(DateUtil.parse(startAt)).endAt(
                    DateUtil.parse(endAt)).uri(EquipStationUtils.GET_WATER_QUALITY_PAGE_URI).build();
            sysEquipStationDataLogDAO.insert(build);
        }
    }

    /**
     * 查询列表
     *
     * @param districtCode 行政区划编码
     * @param type         监测站类型（1:气象站，2:水文站）
     * @param status       状态：1-在线 0-离线
     * @param name         名称
     * @param current      当前页数
     * @param size         每页条数
     *
     * @return DistrictCountDTO
     */
    @Override
    public PageData<List<SysEquipStationDTO>> qryList(String districtCode, Integer type, Integer status, String name,
                                                      Integer current, Integer size) {
        //判断在离线：6个小时之内是否有数据推送过来
        Date now = new Date();
        String end = DateUtil.format(now, DatePattern.NORM_DATETIME_PATTERN);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(now);
        calendar.add(Calendar.HOUR_OF_DAY, -6);
        String start = DateUtil.format(calendar.getTime(), DatePattern.NORM_DATETIME_PATTERN);
        long total = sysEquipStationDAO.count(districtCode, true, type, status, name, start, end);
        if (total == 0) {
            return PageData.<List<SysEquipStationDTO>>builder()
                    .count((int) total)
                    .size(size)
                    .current(current)
                    .datas(new ArrayList<>())
                    .build();
        }

        Integer offset = (current - 1) * size;

        List<SysEquipStation> sysEquipStations = sysEquipStationDAO.selectByCondition(districtCode, true, type, status,
                name, start, end, size, offset);
        sysEquipStations = sysEquipStations.stream().peek(
                sysEquipStation -> {sysEquipStation.setOnlineStatus(sysEquipStation.isStatus() ? 1 : 0);}).collect(
                Collectors.toList());
        List<SysEquipStationDTO> sysEquipStationDTOS = sysEquipStations.stream().map(
                map -> Convert.convert(SysEquipStationDTO.class, map)).collect(
                Collectors.toList());

        return PageData.<List<SysEquipStationDTO>>builder()
                .count((int) total)
                .size(size)
                .current(current)
                .datas(sysEquipStationDTOS)
                .build();
    }

}
